package com.xadmin.sys.common.coding;

import cn.hutool.core.io.FileUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.db.Db;
import cn.hutool.db.Entity;
import com.xadmin.sys.common.response.Result;
import com.alibaba.druid.pool.DruidDataSource;
import com.baomidou.mybatisplus.annotation.DbType;
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.generator.AutoGenerator;
import com.baomidou.mybatisplus.generator.config.*;
import com.baomidou.mybatisplus.generator.config.rules.DateType;
import com.baomidou.mybatisplus.generator.config.rules.NamingStrategy;
import org.apache.commons.compress.utils.Lists;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RestController;

import java.io.*;
import java.sql.SQLException;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

@RestController
public class Coding {

    private static Map<String,String> searchMap = new HashMap();
    // 模板位置
    private static final String tmpBasePath = System.getProperty("user.dir") + "/xadmin-master/src/test/templates/";
    /**
     *  java生成位置
     */
    private static final String javaBasePath = System.getProperty("user.dir") + "/xadmin-master/src/main/java/com/xadmin/designing/";
    private static final String xmlBasePath = System.getProperty("user.dir") +"/xadmin-master/src/main/resources/mapper/";

    private static final DruidDataSource ds = new DruidDataSource();

    @RequestMapping(value = "/coding",method = RequestMethod.POST)
    public Result create(@RequestBody TableCoding tableCoding) throws SQLException {
        ds.setUrl("jdbc:mysql://localhost:3306/" + tableCoding.getSchemaName() + "?useUnicode=true&characterEncoding=utf-8&allowMultiQueries=true&useSSL=false&serverTimezone=GMT%2b8");
        ds.setUsername(tableCoding.getUserName());
        ds.setPassword(tableCoding.getPassword());
        searchMap.put("cols",tableCoding.getCols());
        createCode(tableCoding.getModeName(),tableCoding.getTableName(),tableCoding.getProjectPath(),tableCoding.getUserName(),tableCoding.getPassword(),tableCoding.getSchemaName());
        return  Result.ok().message("代码生成成功！");
    }


    public static void createCode(String modeName,String tableName,String projectPath,String userName,String password,String schemaName) throws SQLException {
        Map<String, String> map = new HashMap<>();
        map.put("modeName",modeName);
        map.put("tableName", StrUtil.removePrefix(tableName, "tb_"));

        List<TableColumn> tableColumns = getTableColumns(tableName,schemaName);
        // list
        StringBuilder listBuilder = new StringBuilder();
        // add && update
        StringBuilder addBuilder = new StringBuilder();
        // search
        StringBuilder searchBuilder = new StringBuilder();

        for (TableColumn tableColumn : tableColumns) {

            if(searchMap.get("cols").equals(tableColumn.getColumnName())){
                searchBuilder.append("<el-form-item label=\""+tableColumn.getColumnComment()+"\">");
                searchBuilder.append("\n");
                searchBuilder.append("<el-input v-model=\"page.params."+ StrUtil.toCamelCase(tableColumn.getColumnName()) +"\" placeholder=\"请输入"+tableColumn.getColumnComment()+"\" clearable />");
                searchBuilder.append("\n");
                searchBuilder.append("</el-form-item>");
                searchBuilder.append("\n");
            }


            if (tableColumn.getColumnName().equals("id")) {
                listBuilder.append("<el-table-column v-if=\"false\" align=\"center\" prop=\"" + StrUtil.toCamelCase(tableColumn.getColumnName()) + "\" label=\"" + tableColumn.getColumnComment() + "\"></el-table-column>\n");
            }else
            if(tableColumn.getColumnName().equals("img")){
                listBuilder.append("<el-table-column label=\"图片\">"+"\n");
                listBuilder.append("<template slot-scope=\"scope\" v-if=\"scope.row.img\">"+"\n");
                listBuilder.append("<img style=\"width:30px;height:30px\" :src=\"scope.row.img\" />"+"\n");
                listBuilder.append("</template>"+"\n"+"</el-table-column>"+"\n");
            }else if(tableColumn.getColumnName().endsWith("edit")){

            } else{
                listBuilder.append("<el-table-column align=\"center\" prop=\"" + StrUtil.toCamelCase(tableColumn.getColumnName()) + "\" label=\"" + tableColumn.getColumnComment() + "\"></el-table-column>\n");
            }


            if(tableColumn.getColumnName().equals("id")){

            }else if(tableColumn.getColumnName().endsWith("edit")){
               addBuilder.append("<el-form-item label=\""+ tableColumn.getColumnComment() +"\">");
               addBuilder.append("<MyEditor :msg.sync=\"dataList."+StrUtil.toCamelCase(tableColumn.getColumnName())+"\"></MyEditor>");
               addBuilder.append("</el-form-item>");
            } else if(tableColumn.getColumnName().endsWith("radio")){

                String columnComment = tableColumn.getColumnComment();
                String[] split = columnComment.split(",");
                addBuilder.append("<el-form-item label=\""+ tableColumn.getColumnComment() +"\">");
                addBuilder.append("<el-radio-group v-model=\"dataList." + StrUtil.toCamelCase(tableColumn.getColumnName()) + "\">");
                for (String s : split) {
                    addBuilder.append("<el-radio :label=\""+ s +"\">"+ s +"</el-radio>");
                }
                addBuilder.append("</el-radio-group>");
                addBuilder.append("</el-form-item>");
            }else if(tableColumn.getColumnName().equals("img")){

                addBuilder.append("<el-form-item label=\"图片\">"+"\n");
                addBuilder.append("<el-upload action=\"api/upload\" :headers=\"headers\" :file-list=\"fileList\" list-type=\"picture-card\" :class=\"{disabled:uploadDisabled}\"  :on-remove=\"handleRemove\" :on-success=\"handlePreview\" :limit=\"1\">"+"\n");
                addBuilder.append("<i slot=\"default\" class=\"el-icon-plus\"></i>"+"\n");
                addBuilder.append("</el-upload>"+"\n"+"</el-form-item>");
            }else {
                addBuilder.append("<el-form-item label=\"" + tableColumn.getColumnComment() + "\"><el-input v-model=\"dataList." + StrUtil.toCamelCase(tableColumn.getColumnName()) + "\"></el-input></el-form-item>");
                addBuilder.append("\n");
            }
        }
        map.put("listBuilder",listBuilder.toString());
        map.put("addBuilder",addBuilder.toString());
        map.put("searchBuilder",searchBuilder.toString());

        String format = StrUtil.format(FileUtil.readUtf8String(tmpBasePath+"vue.template"), map);
        FileUtil.writeString(format, projectPath+"/src/views/" + StrUtil.removePrefix(tableName, "tb_") + ".vue", "UTF-8");


        Map apiMap = new HashMap();
        apiMap.put("table",StrUtil.removePrefix(tableName, "tb_"));
        String apiFormat = StrUtil.format(FileUtil.readUtf8String(tmpBasePath+"api.template"), apiMap);
        FileUtil.writeString(apiFormat, projectPath + "/src/api/" + StrUtil.removePrefix(tableName, "tb_") + ".js", "UTF-8");

        getRouter(projectPath+"/src/router/index.js",tableName,modeName);

        String pojo = StrUtil.upperFirst(StrUtil.removePrefix(tableName, "tb_"));
        String mapper = pojo+"Mapper";
        String service = pojo+ "Service";
        Map javaMap = new HashMap();
        javaMap.put("tableName",tableName);
        javaMap.put("modeName",modeName);
        javaMap.put("pojo",pojo);
        javaMap.put("pojos",StrUtil.removePrefix(tableName, "tb_"));
        javaMap.put("mapper",mapper);
        javaMap.put("service",service);

        javaMap.put("cols",searchMap.get("cols"));
        javaMap.put("pojoCols",StrUtil.toCamelCase(searchMap.get("cols")));


        String xmlFormat = StrUtil.format(FileUtil.readUtf8String(tmpBasePath+"xml.template"), javaMap);
        FileUtil.writeString(xmlFormat, xmlBasePath + mapper + ".xml", "UTF-8");


        String controllerFormat = StrUtil.format(FileUtil.readUtf8String(tmpBasePath+"controller.template"), javaMap);
        FileUtil.writeString(controllerFormat, javaBasePath+"controller/" + pojo + "Controller.java", "UTF-8");


        String mapperFormat = StrUtil.format(FileUtil.readUtf8String(tmpBasePath+"mapper.template"), javaMap);
        FileUtil.writeString(mapperFormat, javaBasePath+"mapper/" + mapper + ".java", "UTF-8");


        String serviceFormat = StrUtil.format(FileUtil.readUtf8String(tmpBasePath+"service.template"), javaMap);
        FileUtil.writeString(serviceFormat, javaBasePath+"service/" + service + ".java", "UTF-8");


        String implFormat = StrUtil.format(FileUtil.readUtf8String(tmpBasePath+"impl.template"), javaMap);
        FileUtil.writeString(implFormat, javaBasePath+"service/impl/" + service + "Impl.java", "UTF-8");

        createPojo( tableName, schemaName, userName, password);
    }


    static List<TableColumn> getTableColumns(String tableName,String schemaName) throws SQLException {
        String sql = "SELECT table_name,column_name,data_type, column_comment FROM information_schema.COLUMNS WHERE table_schema = ? and table_name = ?";
        List<Entity> user = Db.use(ds).query(sql, schemaName, tableName);
        List<TableColumn> columnList = Lists.newArrayList();
        for (Entity entity : user) {
            TableColumn tableColumn = new TableColumn();
            tableColumn.setTableName(entity.getStr("table_name"));
            tableColumn.setColumnName(entity.getStr("column_name"));
            tableColumn.setColumnComment(entity.getStr("column_comment"));
            columnList.add(tableColumn);
        }
        return columnList;
    }

    static void createPojo(String tableName,String schemaName,String userName,String password ){
        // 创建代码生成器对象
        AutoGenerator mpg = new AutoGenerator();

        // 全局配置
        GlobalConfig gc = new GlobalConfig();
        gc.setOutputDir(System.getProperty("user.dir") + "/xadmin-master/src/main/java");
        gc.setOpen(false);
        //重新生成时是否覆盖文件
        gc.setFileOverride(false);
        //设置主键生成策略  自动增长
        gc.setIdType(IdType.AUTO);
        //设置Date的类型   只使用 java.util.date 代替
        gc.setDateType(DateType.ONLY_DATE);
        //开启实体属性 Swagger2 注解
        gc.setSwagger2(true);
        mpg.setGlobalConfig(gc);

        TemplateConfig templateConfig = new TemplateConfig();
        templateConfig.disable(TemplateType.CONTROLLER);
        templateConfig.disable(TemplateType.XML);
        templateConfig.disable(TemplateType.MAPPER);
        templateConfig.disable(TemplateType.SERVICE);
        templateConfig.disable(TemplateType.SERVICE);
        mpg.setTemplate(templateConfig);
        // 数据源配置
        DataSourceConfig dsc = new DataSourceConfig();
        dsc.setUrl("jdbc:mysql://localhost:3306/"+schemaName+"?useUnicode=true&characterEncoding=UTF-8&serverTimezone=GMT%2B8");
        dsc.setDriverName("com.mysql.cj.jdbc.Driver");
        dsc.setUsername(userName);
        dsc.setPassword(password);
        //使用mysql数据库
        dsc.setDbType(DbType.MYSQL);
        mpg.setDataSource(dsc);

        // 包配置
        PackageConfig pc = new PackageConfig();
        pc.setModuleName("designing");
        pc.setParent("com.xadmin");
        pc.setEntity("pojo");
        mpg.setPackageInfo(pc);

        // 策略配置
        StrategyConfig strategy = new StrategyConfig();
        //设置哪些表需要自动生成
        strategy.setInclude(tableName);
        //实体类名称驼峰命名
        strategy.setNaming(NamingStrategy.underline_to_camel);
        //列名名称驼峰命名
        strategy.setColumnNaming(NamingStrategy.underline_to_camel);
        //使用简化getter和setter
        strategy.setEntityLombokModel(true);
        //设置controller的api风格  使用RestController
        strategy.setRestControllerStyle(true);
        //驼峰转连字符
        strategy.setControllerMappingHyphenStyle(true);
        //忽略表中生成实体类的前缀
        strategy.setTablePrefix("tb_");
        mpg.setStrategy(strategy);
        mpg.execute();
    }

    public static void getRouter(String filePath,String tableName,String modelName)  {
         try{
             StringBuilder builder = new StringBuilder();
             builder.append("\n");
             builder.append("{").append("\n");
             builder.append("path: '/").append(tableName).append("',").append("\n");
             builder.append("name: '").append(StrUtil.upperFirst(tableName)).append("',").append("\n");
             builder.append("component: () => import('@/views/").append(tableName).append("'),").append("\n");
             builder.append("meta: {title: `").append(modelName).append("`}").append("\n");
             builder.append("},").append("\n");
             insert(filePath,2670,builder.toString());
         }catch (Exception e){
             e.printStackTrace();
         }
    }

    public static void insert(String filePath,long pos,String insertContent)throws IOException{
        RandomAccessFile raf=null;
        File tmp=File.createTempFile("tmp",null);
        tmp.deleteOnExit();
        try {
            // 以读写的方式打开一个RandomAccessFile对象
            raf = new RandomAccessFile(new File(filePath), "rw");
            //创建一个临时文件来保存插入点后的数据
            FileOutputStream fileOutputStream = new FileOutputStream(tmp);
            FileInputStream fileInputStream = new FileInputStream(tmp);
            //把文件记录指针定位到pos位置
            raf.seek(pos);
            raf.seek(pos);
            //------下面代码将插入点后的内容读入临时文件中保存-----
            byte[] bbuf = new byte[64];
            //用于保存实际读取的字节数据
            int hasRead = 0;
            //使用循环读取插入点后的数据
            while ((hasRead = raf.read(bbuf)) != -1) {
                //将读取的内容写入临时文件
                fileOutputStream.write(bbuf, 0, hasRead);
            }
            //-----下面代码用于插入内容 -----
            //把文件记录指针重新定位到pos位置
            raf.seek(pos);
            //追加需要插入的内容
            raf.write(insertContent.getBytes());
            //追加临时文件中的内容
            while ((hasRead = fileInputStream.read(bbuf)) != -1) {
                //将读取的内容写入临时文件
                raf.write(bbuf, 0, hasRead);
            }
        }catch (Exception e){
            throw  e;
        }
    }




}
